home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / CONTRIB / STEAM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  14.7 KB  |  622 lines

  1. /**
  2.  
  3.   Description: Interactive 3D graphics, Assignment #1
  4.                Miniature Steam Engine Simulation.
  5.   Author:      Troy Robinette
  6.   Date:        29/9/95
  7.   Email:       troyr@yallara.cs.rmit.edu.au
  8.   Notes:       - Transparence doesn't quite work. The color of the
  9.                  underlying object doesn't show through. 
  10.            - Also only the front side of the transparent objects are
  11.          transparent.
  12.  
  13. **/
  14.  
  15. #include <stdio.h>
  16. #include <GL/glut.h>
  17. #include <math.h>
  18.  
  19. #define TRUE  1
  20. #define FALSE 0
  21.  
  22. /* Dimensions of texture image. */
  23. #define IMAGE_WIDTH  64
  24. #define IMAGE_HEIGHT 64
  25.  
  26. /* Step to be taken for each rotation. */
  27. #define ANGLE_STEP 10
  28.  
  29. /* Magic numbers for relationship b/w cylinder head and crankshaft. */
  30. #define MAGNITUDE  120
  31. #define PHASE      270.112
  32. #define FREQ_DIV   58
  33. #define ARC_LENGHT 2.7
  34. #define ARC_RADIUS 0.15
  35.  
  36. /* Rotation angles */
  37. GLdouble view_h = 270, view_v = 0, head_angle = 0;
  38. GLint crank_angle = 0;
  39.  
  40. /* Crank rotation step. */
  41. GLdouble crank_step = 5;
  42.  
  43. /* Toggles */
  44. GLshort shaded = TRUE, anim = FALSE;
  45. GLshort texture = FALSE, transparent = FALSE;
  46. GLshort light1 = TRUE, light2 = FALSE;
  47.  
  48. /* Storage for the angle look up table and the texture map */
  49. GLdouble head_look_up_table[361];
  50. GLubyte image[IMAGE_WIDTH][IMAGE_HEIGHT][3];
  51.  
  52. /* Indentifiers for each Display list */
  53. GLint list_piston_shaded = 1;
  54. GLint list_piston_texture = 2;
  55. GLint list_flywheel_shaded = 4;
  56. GLint list_flywheel_texture = 8;
  57.  
  58. /* Variable used in the creaton of glu objects */
  59. GLUquadricObj *obj;
  60.  
  61. /* Draws a box by scaling a glut cube of size 1. Also checks the shaded 
  62.    toggle to see which rendering style to use. NB Texture doesn't work
  63.    correctly due to the cube being scaled. */
  64. void 
  65. myBox(GLdouble x, GLdouble y, GLdouble z)
  66. {
  67.   glPushMatrix();
  68.     glScalef(x, y, z);
  69.     if (shaded)
  70.       glutSolidCube(1);
  71.     else
  72.       glutWireCube(1);
  73.   glPopMatrix();
  74. }
  75.  
  76. /* Draws a cylinder using glu function, drawing flat disc's at each end,
  77.    to give the appearence of it being solid. */
  78. void 
  79. myCylinder(GLUquadricObj * object, GLdouble outerRadius,
  80.   GLdouble innerRadius, GLdouble lenght)
  81. {
  82.   glPushMatrix();
  83.     gluCylinder(object, outerRadius, outerRadius, lenght, 20, 1);
  84.     glPushMatrix();
  85.       glRotatef(180, 0.0, 1.0, 0.0);
  86.       gluDisk(object, innerRadius, outerRadius, 20, 1);
  87.     glPopMatrix();
  88.  
  89.     glTranslatef(0.0, 0.0, lenght);
  90.     gluDisk(object, innerRadius, outerRadius, 20, 1);
  91.   glPopMatrix();
  92. }
  93.  
  94. /* Draws a piston.  */
  95. void 
  96. draw_piston(void)
  97. {
  98.   glPushMatrix();
  99.     glColor4f(0.3, 0.6, 0.9, 1.0);
  100.  
  101.     glPushMatrix();
  102.       glRotatef(90, 0.0, 1.0, 0.0);
  103.       glTranslatef(0.0, 0.0, -0.07);
  104.       myCylinder(obj, 0.125, 0.06, 0.12);
  105.     glPopMatrix();
  106.  
  107.     glRotatef(-90, 1.0, 0.0, 0.0);
  108.     glTranslatef(0.0, 0.0, 0.05);
  109.     myCylinder(obj, 0.06, 0.0, 0.6);
  110.     glTranslatef(0.0, 0.0, 0.6);
  111.     myCylinder(obj, 0.2, 0.0, 0.5);
  112.   glPopMatrix();
  113. }
  114.  
  115. /* Draws the engine pole and the pivot pole for the cylinder head. */
  116. void 
  117. draw_engine_pole(void)
  118. {
  119.   glPushMatrix();
  120.     glColor4f(0.9, 0.9, 0.9, 1.0);
  121.     myBox(0.5, 3.0, 0.5);
  122.  
  123.     glColor3f(0.5, 0.1, 0.5);
  124.     glRotatef(90, 0.0, 1.0, 0.0);
  125.     glTranslatef(0.0, 0.9, -0.4);
  126.     myCylinder(obj, 0.1, 0.0, 2);
  127.   glPopMatrix();
  128. }
  129.  
  130. /* Draws the cylinder head at the appropreate angle, doing the necesary 
  131.    translations for the rotation. */
  132. void 
  133. draw_cylinder_head(void)
  134. {
  135.   glPushMatrix();
  136.     glColor4f(0.5, 1.0, 0.5, 0.1);
  137.     glRotatef(90, 1.0, 0.0, 0.0);
  138.     glTranslatef(0, 0.0, 0.4);
  139.     glRotatef(head_angle, 1, 0, 0);
  140.     glTranslatef(0, 0.0, -0.4);
  141.     myCylinder(obj, 0.23, 0.21, 1.6);
  142.     glRotatef(180, 1.0, 0.0, 0.0);
  143.     gluDisk(obj, 0, 0.23, 20, 1);
  144.   glPopMatrix();
  145. }
  146.  
  147. /* Draws the flywheel.  */
  148. void 
  149. draw_flywheel(void)
  150. {
  151.   glPushMatrix();
  152.     glColor4f(0.5, 0.5, 1.0, 1.0);
  153.     glRotatef(90, 0.0, 1.0, 0.0);
  154.     myCylinder(obj, 0.625, 0.08, 0.5);
  155.   glPopMatrix();
  156. }
  157.  
  158. /* Draws the crank bell, and the pivot pin for the piston. Also calls the
  159.    appropreate display list of a piston doing the nesacary rotations before
  160.    hand.  */
  161. void 
  162. draw_crankbell(void)
  163. {
  164.   glPushMatrix();
  165.     glColor4f(1.0, 0.5, 0.5, 1.0);
  166.     glRotatef(90, 0.0, 1.0, 0.0);
  167.     myCylinder(obj, 0.3, 0.08, 0.12);
  168.  
  169.     glColor4f(0.5, 0.1, 0.5, 1.0);
  170.     glTranslatef(0.0, 0.2, 0.0);
  171.     myCylinder(obj, 0.06, 0.0, 0.34);
  172.  
  173.     glTranslatef(0.0, 0.0, 0.22);
  174.     glRotatef(90, 0.0, 1.0, 0.0);
  175.     glRotatef(crank_angle - head_angle, 1.0, 0.0, 0.0);
  176.     if (shaded) {
  177.       if (texture)
  178.         glCallList(list_piston_texture);
  179.       else
  180.         glCallList(list_piston_shaded);
  181.     } else
  182.       draw_piston();
  183.   glPopMatrix();
  184. }
  185.  
  186. /* Draws the complete crank. Piston also gets drawn through the crank bell
  187.    function. */
  188. void 
  189. draw_crank(void)
  190. {
  191.   glPushMatrix();
  192.     glRotatef(crank_angle, 1.0, 0.0, 0.0);
  193.  
  194.     glPushMatrix();
  195.       glRotatef(90, 0.0, 1.0, 0.0);
  196.       glTranslatef(0.0, 0.0, -1.0);
  197.       myCylinder(obj, 0.08, 0.0, 1.4);
  198.     glPopMatrix();
  199.  
  200.     glPushMatrix();
  201.       glTranslatef(0.28, 0.0, 0.0);
  202.       draw_crankbell();
  203.     glPopMatrix();
  204.  
  205.     glPushMatrix();
  206.       glTranslatef(-0.77, 0.0, 0.0);
  207.       if (shaded) {
  208.         if (texture)
  209.           glCallList(list_flywheel_texture);
  210.         else
  211.           glCallList(list_flywheel_shaded);
  212.       } else
  213.         draw_flywheel();
  214.     glPopMatrix();
  215.   glPopMatrix();
  216. }
  217.  
  218. /* Main display routine. Clears the drawing buffer and if transparency is
  219.    set, displays the model twice, 1st time accepting those fragments with 
  220.    a ALPHA value of 1 only, then with DEPTH_BUFFER writing disabled for 
  221.    those with other values. */
  222. void 
  223. display(void)
  224. {
  225.   int pass;
  226.  
  227.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  228.  
  229.   glPushMatrix();
  230.     if (transparent) {
  231.       glEnable(GL_ALPHA_TEST);
  232.       pass = 2;
  233.     } else {
  234.       glDisable(GL_ALPHA_TEST);
  235.       pass = 0;
  236.     }
  237.  
  238.     /* Rotate the whole model */
  239.     glRotatef(view_h, 0, 1, 0);
  240.     glRotatef(view_v, 1, 0, 0);
  241.  
  242.     do {
  243.       if (pass == 2) {
  244.         glAlphaFunc(GL_EQUAL, 1);
  245.         glDepthMask(GL_TRUE);
  246.         pass--;
  247.       } else if (pass != 0) {
  248.         glAlphaFunc(GL_NOTEQUAL, 1);
  249.         glDepthMask(GL_FALSE);
  250.         pass--;
  251.       }
  252.       draw_engine_pole();
  253.  
  254.       glPushMatrix();
  255.         glTranslatef(0.5, 1.4, 0.0);
  256.         draw_cylinder_head();
  257.       glPopMatrix();
  258.  
  259.       glPushMatrix();
  260.         glTranslatef(0.0, -0.8, 0.0);
  261.         draw_crank();
  262.       glPopMatrix();
  263.     } while (pass > 0);
  264.     glDepthMask(GL_TRUE);
  265.     glutSwapBuffers();
  266.   glPopMatrix();
  267. }
  268.  
  269. /* Called when the window is idle. When called increments the crank angle
  270.    by ANGLE_STEP, updates the head angle and notifies the system that
  271.    the screen needs to be updated. */
  272. void 
  273. animation(void)
  274. {
  275.   if ((crank_angle += crank_step) >= 360)
  276.     crank_angle = 0;
  277.   head_angle = head_look_up_table[crank_angle];
  278.   glutPostRedisplay();
  279. }
  280.  
  281. /* Called when a key is pressed. Checks if it reconises the key and if so
  282.    acts on it, updateing the screen. */
  283. /* ARGSUSED1 */
  284. void 
  285. keyboard(unsigned char key, int x, int y)
  286. {
  287.   switch (key) {
  288.   case 's':
  289.     if (shaded == FALSE) {
  290.       shaded = TRUE;
  291.       glShadeModel(GL_SMOOTH);
  292.       glEnable(GL_LIGHTING);
  293.       glEnable(GL_DEPTH_TEST);
  294.       glEnable(GL_COLOR_MATERIAL);
  295.       gluQuadricNormals(obj, GLU_SMOOTH);
  296.       gluQuadricDrawStyle(obj, GLU_FILL);
  297.     } else {
  298.       shaded = FALSE;
  299.       glShadeModel(GL_FLAT);
  300.       glDisable(GL_LIGHTING);
  301.       glDisable(GL_DEPTH_TEST);
  302.       glDisable(GL_COLOR_MATERIAL);
  303.       gluQuadricNormals(obj, GLU_NONE);
  304.       gluQuadricDrawStyle(obj, GLU_LINE);
  305.       gluQuadricTexture(obj, GL_FALSE);
  306.     }
  307.     if (texture && !shaded);
  308.     else
  309.       break;
  310.   case 't':
  311.     if (texture == FALSE) {
  312.       texture = TRUE;
  313.       glEnable(GL_TEXTURE_2D);
  314.       gluQuadricTexture(obj, GL_TRUE);
  315.     } else {
  316.       texture = FALSE;
  317.       glDisable(GL_TEXTURE_2D);
  318.       gluQuadricTexture(obj, GL_FALSE);
  319.     }
  320.     break;
  321.   case 'o':
  322.     if (transparent == FALSE) {
  323.       transparent = TRUE;
  324.     } else {
  325.       transparent = FALSE;
  326.     }
  327.     break;
  328.  
  329.   case 'a':
  330.     if ((crank_angle += crank_step) >= 360)
  331.       crank_angle = 0;
  332.     head_angle = head_look_up_table[crank_angle];
  333.     break;
  334.   case 'z':
  335.     if ((crank_angle -= crank_step) <= 0)
  336.       crank_angle = 360;
  337.     head_angle = head_look_up_table[crank_angle];
  338.     break;
  339.   case '0':
  340.     if (light1) {
  341.       glDisable(GL_LIGHT0);
  342.       light1 = FALSE;
  343.     } else {
  344.       glEnable(GL_LIGHT0);
  345.       light1 = TRUE;
  346.     }
  347.     break;
  348.   case '1':
  349.     if (light2) {
  350.       glDisable(GL_LIGHT1);
  351.       light2 = FALSE;
  352.     } else {
  353.       glEnable(GL_LIGHT1);
  354.       light2 = TRUE;
  355.     }
  356.     break;
  357.   case '4':
  358.     if ((view_h -= ANGLE_STEP) <= 0)
  359.       view_h = 360;
  360.     break;
  361.   case '6':
  362.     if ((view_h += ANGLE_STEP) >= 360)
  363.       view_h = 0;
  364.     break;
  365.   case '8':
  366.     if ((view_v += ANGLE_STEP) >= 360)
  367.       view_v = 0;
  368.     break;
  369.   case '2':
  370.     if ((view_v -= ANGLE_STEP) <= 0)
  371.       view_v = 360;
  372.     break;
  373.   case ' ':
  374.     if (anim) {
  375.       glutIdleFunc(0);
  376.       anim = FALSE;
  377.     } else {
  378.       glutIdleFunc(animation);
  379.       anim = TRUE;
  380.     }
  381.     break;
  382.   case '+':
  383.     if ((++crank_step) > 45)
  384.       crank_step = 45;
  385.     break;
  386.   case '-':
  387.     if ((--crank_step) <= 0)
  388.       crank_step = 0;
  389.     break;
  390.   default:
  391.     return;
  392.   }
  393.   glutPostRedisplay();
  394. }
  395.  
  396. /* ARGSUSED1 */
  397. void
  398. special(int key, int x, int y)
  399. {
  400.   switch (key) {
  401.   case GLUT_KEY_LEFT:
  402.     if ((view_h -= ANGLE_STEP) <= 0)
  403.       view_h = 360;
  404.     break;
  405.   case GLUT_KEY_RIGHT:
  406.     if ((view_h += ANGLE_STEP) >= 360)
  407.       view_h = 0;
  408.     break;
  409.   case GLUT_KEY_UP:
  410.     if ((view_v += ANGLE_STEP) >= 360)
  411.       view_v = 0;
  412.     break;
  413.   case GLUT_KEY_DOWN:
  414.     if ((view_v -= ANGLE_STEP) <= 0)
  415.       view_v = 360;
  416.     break;
  417.   default:
  418.     return;
  419.   }
  420.   glutPostRedisplay();
  421. }
  422.  
  423. /* Called when a menu option has been selected. Translates the menu item
  424.    identifier into a keystroke, then call's the keyboard function. */
  425. void 
  426. menu(int val)
  427. {
  428.   unsigned char key;
  429.  
  430.   switch (val) {
  431.   case 1:
  432.     key = 's';
  433.     break;
  434.   case 2:
  435.     key = ' ';
  436.     break;
  437.   case 3:
  438.     key = 't';
  439.     break;
  440.   case 4:
  441.     key = 'o';
  442.     break;
  443.   case 5:
  444.     key = '0';
  445.     break;
  446.   case 6:
  447.     key = '1';
  448.     break;
  449.   case 7:
  450.     key = '+';
  451.     break;
  452.   case 8:
  453.     key = '-';
  454.     break;
  455.   default:
  456.     return;
  457.   }
  458.   keyboard(key, 0, 0);
  459. }
  460.  
  461. /* Initialises the menu of toggles. */
  462. void 
  463. create_menu(void)
  464. {
  465.   glutCreateMenu(menu);
  466.   glutAttachMenu(GLUT_LEFT_BUTTON);
  467.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  468.   glutAddMenuEntry("Shaded", 1);
  469.   glutAddMenuEntry("Animation", 2);
  470.   glutAddMenuEntry("Texture", 3);
  471.   glutAddMenuEntry("Transparency", 4);
  472.   glutAddMenuEntry("Right Light (0)", 5);
  473.   glutAddMenuEntry("Left Light (1)", 6);
  474.   glutAddMenuEntry("Speed UP", 7);
  475.   glutAddMenuEntry("Slow Down", 8);
  476. }
  477.  
  478. /* Makes a simple check pattern image. (Copied from the redbook example
  479.    "checker.c".) */
  480. void
  481. make_image(void)
  482. {
  483.   int i, j, c;
  484.  
  485.   for (i = 0; i < IMAGE_WIDTH; i++) {
  486.     for (j = 0; j < IMAGE_HEIGHT; j++) {
  487.       c = (((i & 0x8) == 0) ^ ((j & 0x8) == 0)) * 255;
  488.       image[i][j][0] = (GLubyte) c;
  489.       image[i][j][1] = (GLubyte) c;
  490.       image[i][j][2] = (GLubyte) c;
  491.     }
  492.   }
  493. }
  494.  
  495. /* Makes the head look up table for all possible crank angles. */
  496. void 
  497. make_table(void)
  498. {
  499.   GLint i;
  500.   GLdouble k;
  501.  
  502.   for (i = 0, k = 0.0; i < 360; i++, k++) {
  503.     head_look_up_table[i] =
  504.       MAGNITUDE * atan(
  505.       (ARC_RADIUS * sin(PHASE - k / FREQ_DIV)) /
  506.       ((ARC_LENGHT - ARC_RADIUS * cos(PHASE - k / FREQ_DIV))));
  507.   }
  508. }
  509.  
  510. /* Initialises texturing, lighting, display lists, and everything else 
  511.    associated with the model. */
  512. void 
  513. myinit(void)
  514. {
  515.   GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
  516.   GLfloat mat_shininess[] = {50.0};
  517.   GLfloat light_position1[] = {1.0, 1.0, 1.0, 0.0};
  518.   GLfloat light_position2[] = {-1.0, 1.0, 1.0, 0.0};
  519.  
  520.   glClearColor(0.0, 0.0, 0.0, 0.0);
  521.  
  522.   obj = gluNewQuadric();
  523.   make_table();
  524.   make_image();
  525.  
  526.   /* Set up Texturing */
  527.   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  528.   glTexImage2D(GL_TEXTURE_2D, 0, 3, IMAGE_WIDTH,
  529.     IMAGE_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE,
  530.     image);
  531.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  532.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  533.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  534.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  535.   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  536.  
  537.   /* Set up Lighting */
  538.   glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
  539.   glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
  540.   glLightfv(GL_LIGHT0, GL_POSITION, light_position1);
  541.   glLightfv(GL_LIGHT1, GL_POSITION, light_position2);
  542.  
  543.   /* Initial render mode is with full shading and LIGHT 0
  544.      enabled. */
  545.   glEnable(GL_LIGHTING);
  546.   glEnable(GL_LIGHT0);
  547.   glDepthFunc(GL_LEQUAL);
  548.   glEnable(GL_DEPTH_TEST);
  549.   glDisable(GL_ALPHA_TEST);
  550.  
  551.   glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
  552.   glEnable(GL_COLOR_MATERIAL);
  553.   glShadeModel(GL_SMOOTH);
  554.  
  555.   /* Initialise display lists */
  556.   glNewList(list_piston_shaded, GL_COMPILE);
  557.     draw_piston();
  558.   glEndList();
  559.   glNewList(list_flywheel_shaded, GL_COMPILE);
  560.     draw_flywheel();
  561.   glEndList();
  562.  
  563.   gluQuadricTexture(obj, GL_TRUE);
  564.   glNewList(list_piston_texture, GL_COMPILE);
  565.     draw_piston();
  566.   glEndList();
  567.   glNewList(list_flywheel_texture, GL_COMPILE);
  568.     draw_flywheel();
  569.   glEndList();
  570.   gluQuadricTexture(obj, GL_FALSE);
  571. }
  572.  
  573. /* Called when the model's window has been reshaped.  */
  574. void 
  575. myReshape(int w, int h)
  576. {
  577.   glViewport(0, 0, w, h);
  578.   glMatrixMode(GL_PROJECTION);
  579.   glLoadIdentity();
  580.   gluPerspective(65.0, (GLfloat) w / (GLfloat) h, 1.0, 20.0);
  581.   glMatrixMode(GL_MODELVIEW);
  582.   glLoadIdentity();
  583.   glTranslatef(0.0, 0.0, -5.0);  /* viewing transform  */
  584.   glScalef(1.5, 1.5, 1.5);
  585. }
  586.  
  587. /* Main program. An interactive model of a miniture steam engine.
  588.    Sets system in Double Buffered mode and initialises all the call-back
  589.    functions. */
  590. int 
  591. main(int argc, char **argv)
  592. {
  593.   puts("Miniature Steam Engine                    Troy Robinette\n");
  594.  
  595.   puts("Keypad Arrow keys (with NUM_LOCK on) rotates object.");
  596.   puts("Rotate crank: 'a' = anti-clock wise 'z' = clock wise");
  597.   puts("Crank Speed : '+' = Speed up by 1   '-' = Slow Down by 1");
  598.   puts("Toggle      : 's' = Shading         't' = Texture");
  599.   puts("            : ' ' = Animation       'o' = Transparency");
  600.   puts("            : '0' = Right Light     '1' = Left Light");
  601.   puts(" Alternatively a pop up menu with all toggles is attached");
  602.   puts("   to the left mouse button.\n");
  603.  
  604.   glutInitWindowSize(400, 400);
  605.   glutInit(&argc, argv);
  606.  
  607.   /* Transperancy won't work properly without GLUT_ALPHA */
  608.   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_MULTISAMPLE);
  609.   glutCreateWindow("Miniature Steam Engine by Troy Robinette");
  610.  
  611.   glutDisplayFunc(display);
  612.   glutKeyboardFunc(keyboard);
  613.   glutSpecialFunc(special);
  614.   create_menu();
  615.  
  616.   myinit();
  617.  
  618.   glutReshapeFunc(myReshape);
  619.   glutMainLoop();
  620.   return 0;             /* ANSI C requires main to return int. */
  621. }
  622.